﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Xml.Serialization;
using System.IO;



//  в данные диспетчеру необходимо добавить куда загружать объект (в отдельный процесс, в текущий домен в текущем процессе, в отдельный домен в текущем процессе )  тогда это не просто список паспортов
//  2. сценарий запуска процесса (типа 1. востановить объект 2. запустить некоторые его функции (инициализация и запуск) хотя этот сценарий можно запускать во время востановления (собственной функцией востановления)
//  



namespace конфигуратор
{


    // сценарий загрузки       рпрпрпр
    //1. этап восстановление объекта и его данных
    // 2 этап - восстановление связей объектов между собой - Запуск Метода ВосстановитьСвязи() для каждого объекта
    // 3 этап - запуск сущностей Вызовом Метода Пуск()

 

    public class диспетчер       
    {
        public static Dictionary<string, диспетчер> СловарьДиспетчеров = new Dictionary<string, диспетчер>();
     
        public Паспорт СвойПаспорт = new Паспорт();
        public bool СохранятьсяПриВыходе { get; set; }
        public bool СохранятьОбъектыПриВыходе { get; set; }
        public bool ВосстанавливатьОбъектыПриВосстановлении { get; set; }

        public ObservableCollection<Паспорт> Хранилище = new ObservableCollection<Паспорт>();

        public диспетчер ()
        {
            ЗаполнитьПаспортДиспетчераПоУмолчанию();
        }

        private void ЗаполнитьПаспортДиспетчераПоУмолчанию ()
        {
            СвойПаспорт.ПолноеИмяТипа = this.GetType().FullName;
            СвойПаспорт.Объект = this;
            СвойПаспорт.Сборка = this.GetType().Assembly;
            СвойПаспорт.ПолноеИмяСборки = СвойПаспорт.Сборка.FullName;
            СвойПаспорт.АдресСборки = СвойПаспорт.Сборка.CodeBase;
            СвойПаспорт.СвойСохранительВосстановитель = true;
            СвойПаспорт.ИмяМетодаСохранителя = "Сохранить_хранилище_на_диск";
            СвойПаспорт.ИмяМетодаВосстановителя = "Восстановить_хранилище_с_диска";
            СвойПаспорт.АдресСпячки = @"e:\диспетчер";
            СвойПаспорт.Имя = "диспетчер";
            СловарьДиспетчеров.Add( СвойПаспорт.Имя, this );
        }



        // операции с объектами
        public  Результат ДобавитьНовыйОбъект ( Паспорт новыйПаспорт )
        {
            var рез = new Результат();

            if ( НайтиПервыйПаспортПоИмени( новыйПаспорт.Имя ) != null )
            {
                рез.Успешно = false;
                рез.ТекстОшибки = "такое имя уже существует";
                return рез;
            }
            Хранилище.Add( новыйПаспорт );

            рез.Успешно = true;
            рез.Отчет = "добавлен паспорт в хранилище";

            return рез;

        }
      
      

        public Паспорт НайтиПервыйПаспортПоИмени (  string имя )
        {
            try
            {
                return Хранилище.First( паспорт => имя == паспорт.Имя );
            }
            catch
            {
                return null;
            }
        }


        public void УдалитьИзХранилищаБезСохранения ( Паспорт удаляемыйПаспорт )
        {
            Хранилище.Remove( удаляемыйПаспорт );

        }

        public void ОчиститьХранилищеБезСохранения ()
        {
            Хранилище.Clear();
        }

        public void СохранитьХранилищеНаДиск ( string файл )
        {
            var mystream = new FileStream( СвойПаспорт.Файл + ".диспетчер", FileMode.Create );
                var xml = new XmlSerializer( typeof( диспетчер ) );
                xml.Serialize( mystream, this );
            mystream.Close();
        }

        public static диспетчер ВосстановитьХранилищеСДиска ( string файл )   // восстановить диспетчер(результат) из файла(параметр:имя файла) на диске
        {
            //востановить паспорта  - все объекты не активны - не загружены в память
            var диспетчер = ( диспетчер ) Паспорт.ВосcтановитьИзXml( файл, typeof( диспетчер ) );
            диспетчер.СвойПаспорт.Объект = диспетчер;
            СловарьДиспетчеров.Add( диспетчер.СвойПаспорт.Имя, диспетчер );

            if ( диспетчер.ВосстанавливатьОбъектыПриВосстановлении ) диспетчер.ВосстановитьОбъекты();

            диспетчер.УстановитьСвязи();

            return диспетчер;
        }

        public void СохранитьОбъектыНаДиск ()
        {
            foreach ( var паспорт in Хранилище )
            {
                    паспорт.СохранитьСостояниеОбъекта();
            }
        }

        public void ВосстановитьОбъекты ()
        {
            foreach ( Паспорт паспорт in Хранилище )
            {
                try
                {
                    паспорт.ВосстановитьОбъект();
                }
                catch { }
            }
        }

        public void УстановитьСвязи ()
        {
            foreach ( Паспорт паспорт in Хранилище )
            {
                try
                {
                    dynamic o = паспорт.Объект;
                    o.УстановитьСвязь();
                }
                catch { }
            }
        }

        public void РазорватьСвязи ()
        {
            foreach ( Паспорт паспорт in Хранилище )
            {
                try
                {
                    dynamic o = паспорт.Объект;
                    o.РазорватьСвязь();
                }
                catch { }
            }
        }
        public static object НайтиДиспетчер ( string имяДиспетчера)
        {
            return СловарьДиспетчеров[имяДиспетчера];

        }

        public static object НайтиОбъект ( string имяДиспетчера, string имяОбъекта )
        {
            var дис = СловарьДиспетчеров[имяДиспетчера];

            if ( имяОбъекта == дис.СвойПаспорт.Имя ) return дис;
            try
            {
                return дис.Хранилище.First( паспорт => имяОбъекта == паспорт.Имя ).Объект;
            }
            catch
            {
                return null;
            }
        }

        public static object НайтиОбъект ( string имяОбъекта )
        {
            var дис = СловарьДиспетчеров.GetEnumerator().Current.Value;

            if ( имяОбъекта == дис.СвойПаспорт.Имя ) return СловарьДиспетчеров;
            try
            {
                return дис.Хранилище.First( паспорт => имяОбъекта == паспорт.Имя ).Объект;
            }
            catch
            {
                return null;
            }
        }

    }
}